package com.basic.common.utils;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.basic.common.exception.RRException;
import lombok.extern.slf4j.Slf4j;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Slf4j
public class ParamUtils {

    private static final List<String> offsetFields = Arrays.asList("serialVersionUID", "createUserId", "updateUserId", "createTime", "updateTime", "delFlag");

    public static <T> QueryWrapper<T> createQueryWrapperBySort(ParamsModel<T> params) {
        QueryWrapper<T> queryWrapper = basicQueryWrapper(params);
        if (ObjectUtil.isNotEmpty(params.getSort()) && StrUtil.isNotBlank(params.getSort().getSidx()) && StrUtil.isNotBlank(params.getSort().getOrder())) {
            queryWrapper.orderBy(true, StrUtil.equals(params.getSort().getOrder(), "asc", true), StrUtil.toUnderlineCase(params.getSort().getSidx()));
        }
        return queryWrapper;
    }

    public static <T> QueryWrapper<T> createQueryWrapperByDefaultSort(ParamsModel<T> params) {
        QueryWrapper<T> queryWrapper = basicQueryWrapper(params);
        if (ObjectUtil.isNotEmpty(params.getSort()) && StrUtil.isNotBlank(params.getSort().getSidx()) && StrUtil.isNotBlank(params.getSort().getOrder())) {
            queryWrapper.orderBy(true, StrUtil.equals(params.getSort().getOrder(), "asc", true), StrUtil.toUnderlineCase(params.getSort().getSidx()));
        } else {
            queryWrapper.orderBy(true, false, "create_time");
        }
        return queryWrapper;
    }

//    public static <T> QueryWrapper<T> createQueryWrapperByDefaultSort(T params) {
//        QueryWrapper<T> queryWrapper = basicQueryWrapper(params);
//        if (ObjectUtil.isNotEmpty(params.getSort()) && StrUtil.isNotBlank(params.getSort().getSidx()) && StrUtil.isNotBlank(params.getSort().getOrder())) {
//            queryWrapper.orderBy(true, StrUtil.equals(params.getSort().getOrder(), "asc", true), StrUtil.toUnderlineCase(params.getSort().getSidx()));
//        } else {
//            queryWrapper.orderBy(true, false, "create_time");
//        }
//        return queryWrapper;
//    }

    public static <T> QueryWrapper<T> createQueryWrapper(ParamsModel<T> params) {
        return basicQueryWrapper(params);
    }

    private static <T> QueryWrapper<T> basicQueryWrapper(ParamsModel<T> params) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotEmpty(params) && ObjectUtil.isNotEmpty(params.getProject())) {
            queryWrapper.select(params.getSearchFields());
        }
        if (ObjectUtil.isNotEmpty(params.getCondition())) {
            T condition = params.getCondition();
//            Field[] fields = condition.getClass().getDeclaredFields();
            List<Field> fields = getFieldsNotWithAnnotation(condition.getClass(), TableField.class);
            if (ObjectUtil.isNotEmpty(fields)) {
                for (Field field : fields) {
                    Object value = ReflectUtil.getFieldValue(condition, field);
                    if (ObjectUtil.isNotEmpty(value) && !offsetFields.contains(field.getName())) {
                        if (value instanceof String) {
                            queryWrapper.like(StrUtil.toUnderlineCase(field.getName()), StrUtil.toString(value));
                        } else if (value instanceof Date){
                            continue;
                        } else {
                            queryWrapper.eq(StrUtil.toUnderlineCase(field.getName()), value);
                        }
                    }
                }
            }
        }
        return queryWrapper;
    }

    private static <T> QueryWrapper<T> basicQueryWrapper(T condition) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
//        if (ObjectUtil.isNotEmpty(params) && ObjectUtil.isNotEmpty(params.getProject())) {
//            queryWrapper.select(params.getSearchFields());
//        }
        if (ObjectUtil.isNotEmpty(condition)) {
//            Field[] fields = condition.getClass().getDeclaredFields();
            List<Field> fields = getFieldsNotWithAnnotation(condition.getClass(), TableField.class);
            if (ObjectUtil.isNotEmpty(fields)) {
                for (Field field : fields) {
                    Object value = ReflectUtil.getFieldValue(condition, field);
                    if (ObjectUtil.isNotEmpty(value) && !offsetFields.contains(field.getName())) {
                        if (value instanceof String) {
                            queryWrapper.like(StrUtil.toUnderlineCase(field.getName()), StrUtil.toString(value));
                        } else if (value instanceof Date){
                            continue;
                        } else {
                            queryWrapper.eq(StrUtil.toUnderlineCase(field.getName()), value);
                        }
                    }
                }
            }
        }
        return queryWrapper;
    }

    public static List<Field> getFieldsNotWithAnnotation(Class<?> clazz, Class<?> annotationClass) {
        List<Field> fieldsNotWithAnnotation = new ArrayList<>();
        for (Field field : clazz.getDeclaredFields()) {
            if (!field.isAnnotationPresent((Class<Annotation>) annotationClass)) {
                fieldsNotWithAnnotation.add(field);
            }
        }
        return fieldsNotWithAnnotation;
    }

    public static <T> Long validParamsId(ParamsModel<T> params, Class<T> clazz) {
        if (ObjectUtil.isEmpty(params) || ObjectUtil.isEmpty(params.getCondition())) {
            throw new RRException("参数缺失");
        }
        T condition = params.getCondition();
//        Field[] fields = clazz.getDeclaredFields();
        List<Field> fields = getFieldsNotWithAnnotation(clazz, TableField.class);
        for (Field field : fields) {
            Annotation[] annotations = field.getAnnotations();
            for (Annotation annotation : annotations) {
                if (annotation instanceof TableId) {
                    Object value = ReflectUtil.getFieldValue(condition, field);
                    if (ObjectUtil.isEmpty(value)) {
                        throw new RRException("参数缺失");
                    } else {
                        return Long.parseLong(StrUtil.toString(value));
                    }
                }
            }
        }
        throw new RRException("id校验异常");
    }
}
